#include "ota_version.h"
#include "ota_http_curl.h"
#include "cJSON.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
#include <sys/reboot.h>
#include <unistd.h>
#include "log.h"

#define SHA1_DIGEST_LENGTH 20

char *file_to_sha1(const char *filename)
{
    FILE *file = fopen(filename, "rb");
    if (!file)
    {
        perror("无法打开文件");
        return NULL;
    }

    unsigned char digest[SHA1_DIGEST_LENGTH];
    SHA_CTX sha_ctx;
    SHA1_Init(&sha_ctx);

    unsigned char buffer[1024];
    size_t bytes_read;

    while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0)
    {
        SHA1_Update(&sha_ctx, buffer, bytes_read);
    }

    SHA1_Final(digest, &sha_ctx);
    fclose(file);

    // 转换为十六进制字符串
    char *sha1_str = (char *)malloc(SHA1_DIGEST_LENGTH * 2 + 1);
    if (!sha1_str)
    {
        perror("内存分配失败");
        return NULL;
    }

    for (int i = 0; i < SHA1_DIGEST_LENGTH; ++i)
    {
        sprintf(sha1_str + i * 2, "%02x", digest[i]);
    }
    sha1_str[SHA1_DIGEST_LENGTH * 2] = '\0';

    return sha1_str;
}

/**
 * @brief 执行ota更新
 * 步骤：
 * 1 网关程序 通过http请求  获取ota服务器的版本信息
   2解析信息
  3比较版本号
4 如果本地版本号低  http 则下载最新程序
 5用本地的程序生成一个验证码
 6验证码比较
 7重启

 */
int ota_version_update()
{
    //     * 1 网关程序 通过http请求  获取ota服务器的版本信息
    response_body_t *response_body = ota_http_curl_get(OTA_VERSION_URL);
    //     2解析信息
    if (response_body == NULL)
    {
        perror("ota_http_curl_get error");
        return -1;
    }
    cJSON *root = cJSON_Parse(response_body->str);
    cJSON *major_cjson = cJSON_GetObjectItem(root, "major");
    cJSON *minor_cjson = cJSON_GetObjectItem(root, "minor");
    cJSON *patch_cjson = cJSON_GetObjectItem(root, "patch");

    int major_ota = major_cjson->valueint;
    int minor_ota = minor_cjson->valueint;
    int patch_ota = patch_cjson->valueint;

    //    3比较版本号
    if (major_ota > OTA_VERSION_MAJOR ||
        (major_ota == OTA_VERSION_MAJOR && minor_ota > OTA_VERSION_MINOR) ||
        (major_ota == OTA_VERSION_MAJOR && minor_ota == OTA_VERSION_MINOR && patch_ota > OTA_VERSION_PATCH))
    {
        //  4 如果本地版本号低  http 则下载最新程序
        log_info(" 需要更新ota版本:%d.%d.%d", major_ota, minor_ota, patch_ota);
        int ret = ota_http_curl_download(OTA_VERSION_URL_DOWNLOAD, OTA_VERSION_LOCAL_PATH);
        if (ret == -1)
        {
            log_error("下载失败");
            // 资源释放（原代码缺失）
            cJSON_Delete(root);

            free(response_body);
            return -1;
        }

        //   5用本地的程序生成一个验证码
        char *sha1_local = file_to_sha1(OTA_VERSION_LOCAL_PATH);
        //   6验证码比较
        cJSON *sha_cjson = cJSON_GetObjectItem(root, "sha1");
        char *sha1_ota = sha_cjson->valuestring;
        if (strcmp(sha1_local, sha1_ota) == 0)
        {
            log_info("sha1验证成功,重启更新");


            //   7重启
            reboot(RB_AUTOBOOT);
        }
        else
        {
            log_error("sha1验证失败");
            // 删除无效文件
            cJSON_Delete(root);

            free(response_body);
            unlink(OTA_VERSION_LOCAL_PATH);
            return -1;
        }
    }
    cJSON_Delete(root);

    free(response_body);
    return 0;
}

/**
 * @brief 周期性检查ota版本(每日)
 */
void ota_version_check_daily()
{
    while (1)
    {
        sleep(24 * 60 * 60);
        ota_version_update();
    }
}

/**
 * @brief 打印当前版本号
 */
void ota_version_print()
{
    printf("当前版本号:%d.%d.%d\n", OTA_VERSION_MAJOR, OTA_VERSION_MINOR, OTA_VERSION_PATCH);
}